#include "DSA_signer.h"
#include "DSA_System.h"

DSA_signer::DSA_signer(const DSA_System* const s)
	:parent_system(s)
{
	if(parent_system == NULL) throw "Not allowed create a signer before create a system";
	srand(unsigned(time(NULL)));
	generate_parameters();
}

DSA_signer::DSA_signer(const large_uint& private_key, const DSA_System* const s)
	:parent_system(s)
{
	if(parent_system == NULL) throw "Not allowed create a signer before create a system";
	generate_parameters(private_key);
}

#define PUBLIC_P parent_system->get_p()
#define PUBLIC_Q parent_system->get_q()
#define PUBLIC_G parent_system->get_g()

void DSA_signer::generate_parameters()
{
	x = large_uint::random() % (PUBLIC_Q - 1) + 1;

	y = large_uint::pow_m(PUBLIC_G, x, PUBLIC_P);
}
void DSA_signer::generate_parameters(const large_uint& private_key)
{
	x = private_key;

	y = large_uint::pow_m(PUBLIC_G, x, PUBLIC_P);
}

DSA_signature DSA_signer::get_signature(const large_uint &m) const
{
	large_uint k = large_uint::random() % (PUBLIC_Q - 1) + 1;
	DSA_signature result;

	large_uint r = large_uint::pow_m(PUBLIC_G, k,PUBLIC_P) % PUBLIC_Q;
	large_uint s = large_uint::mult_m
					(
						k.inv(PUBLIC_Q), 
						
						large_uint::add_m
						(
							m, 
							large_uint::mult_m(x, r, PUBLIC_Q),
							PUBLIC_Q
						),
						PUBLIC_Q
					);

	result.r = r;
	result.s = s;

	return result;
}
DSA_signature DSA_signer::get_signature_with_subliminal_channel(const large_uint& m, const large_uint& secret) const
{
	large_uint k(secret);
	DSA_signature result;


	

	large_uint r = large_uint::pow_m(PUBLIC_G, k,PUBLIC_P) % PUBLIC_Q;

	large_uint sum = large_uint::add_m
				(
					m, 
							large_uint::mult_m(x, r, PUBLIC_Q),
							PUBLIC_Q
				);

	large_uint s = large_uint::mult_m
					(
						k.inv(PUBLIC_Q), 
						
						large_uint::add_m
						(
							m, 
							large_uint::mult_m(x, r, PUBLIC_Q),
							PUBLIC_Q
						),
						PUBLIC_Q
					);

	result.r = r;
	result.s = s;

	return result;
}

